#include "event_loop.h"
#include "channel.h"
#include "epoll_poller.h"
#include "logger.h"
#include "poller.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/eventfd.h>
#include <unistd.h>

// 防止一个线程创建多个EventLoop thread_local
__thread EventLoop *t_loop_in_this_thread = nullptr;

// 定义默认的Poller IO复用接口超时时间
const int kPollTimeMs = 10000;

int create_eventfd() {
    int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if (evtfd < 0) {
        LOG_FATAL("eventfd error:%d \n", errno);
    }
    return evtfd;
}

EventLoop::EventLoop()
    : looping_(false), quit_(false), call_pending_functors_(false),
      thread_id_(current_thread::tid()), poller_(Poller::new_default_poller(this)),
      wakeup_fd_(create_eventfd()), wakeup_channel_(new Channel(this, wakeup_fd_)) {
    LOG_DEBUG("EventLoop created %p in thread %d \n", this, thread_id_);
    if (t_loop_in_this_thread) {
        LOG_FATAL("Another EventLoop %p exists in this thread %d \n", t_loop_in_this_thread,thread_id_);
    } else {
        t_loop_in_this_thread = this;
    }

    // 设置wakeupfd时间类型以及发生时间背后的回调操作
    wakeup_channel_->set_read_callback(std::bind(&EventLoop::handle_read, this));
    wakeup_channel_->enable_reading();
}

EventLoop::~EventLoop() {
    wakeup_channel_->disable_all();
    wakeup_channel_->remove();
    ::close(wakeup_fd_);
    t_loop_in_this_thread = nullptr;
}

void EventLoop::loop() {
    looping_ = true;
    quit_ = false;

    LOG_INFO("EventLoop %p start looping \n", this);

    while (!quit_) {
        active_channels_.clear();
        // 监听两种fd client_fd wakeup_fd_
        poll_return_time_ = poller_->poll(kPollTimeMs, &active_channels_);
        for (Channel *channel : active_channels_) {
            // Poller监听哪些channel发生事件了，然后上报给EventLoop,通知channel处理相应事件
            channel->handle_event(poll_return_time_);
        }
        // 执行当前EventLoop事件循环需要的处理回调操作
        /*
        IO线程 main_loop accept fd <= channel subloop
        main_loop 事先注册一个回调cb (需要subloop来执行) wakeup subloop
        后，执行下面的方法，执行之前main_loop注册的cb事件
        */
        do_pending_functors();
    }

    LOG_INFO("EventLoop %p stop looping. \n", this);
    looping_ = false;
}

// 退出事件循环 1.loop在自己的线程调用了quit 2.在非loop的线程中，调用loop的quit
void EventLoop::quit() {
    quit_ = true;

    if (!is_in_loop_thread()) // 如果是在其他线程中，调用的quit
                              // 在一个subloop(worker)中，调用了mainloop注册的事件
    {
        wakeup();
    }
}

// 在当前loop中执行cb
void EventLoop::run_in_loop(Functor cb) {
    if (is_in_loop_thread()) // 在当前的loop线程中，执行cb
    {
        cb();
    } else // 在非当前loop中执行cb,就需要唤醒loop所在线程，执行cb
    {
        queue_in_loop(cb);
    }
}

// 把cb放入队列中，唤醒loop所在的线程，执行cb
void EventLoop::queue_in_loop(Functor cb) {
    {
        std::unique_lock<std::mutex> lock(mutex_);
        pending_functors_.emplace_back(cb);
    }

    // 唤醒相应的，需要执行上面回调操作的loop的线程了
    if (!is_in_loop_thread() || call_pending_functors_) // 这里的calling_pending_functors_
                                                        // 逻辑待解释？？？
    {
        wakeup(); // 唤醒loop所在线程
    }
}

void EventLoop::update_channel(Channel *channel) { poller_->update_channel(channel); }

void EventLoop::remove_channel(Channel *channel) { poller_->remove_channel(channel); }

bool EventLoop::has_channel(Channel *channel) { return poller_->has_channel(channel); }

void EventLoop::handle_read() {
    uint64_t one = 1;
    ssize_t n = read(wakeup_fd_, &one, sizeof one);
    if (n != sizeof one) {
        LOG_ERROR("EventLoop::handle_read() reads %d bytes instead of 8", static_cast<int>(n));
    }
}

// 用来唤醒loop所在的线程，向wakeupfd_
// 写一个数据，wakeupChannel就发生读事件，当前loop就会别唤醒
void EventLoop::wakeup() {
    uint64_t one = 1;
    ssize_t n = write(wakeup_fd_, &one, sizeof one);
    if (n != sizeof one) {
        LOG_ERROR("EventLoop wakeup() writes %lu instead of 8 \n", n);
    }
}

void EventLoop::do_pending_functors() {
    std::vector<Functor> functors;
    call_pending_functors_ = true;

    // 这步加锁和我之前的活跃容器给临时容器转数据的做法一致，就是减少活跃容器频繁读写的问题
    {
        std::unique_lock<std::mutex> lock(mutex_);
        functors.swap(pending_functors_);
    }

    for (const Functor &functor : functors) {
        functor(); // 执行当前loop需要执行的回调操作
    }

    call_pending_functors_ = false;
}